package com.lkc.util; // 定义包路径

import java.util.Map; // 导入Map接口
import java.util.concurrent.Executors; // 导入Executors工具类
import java.util.concurrent.ScheduledExecutorService; // 导入定时执行服务接口
import java.util.concurrent.ScheduledThreadPoolExecutor; // 导入定时线程池执行器类
import java.util.concurrent.TimeUnit; // 导入时间单位枚举类

/**
 * ExpiryMap类 - 一个支持自动过期的Map实现
 */
public class ExpiryMap {
    // 用来存储数据的容器
    private Map<String, Object> map = new java.util.HashMap<String, Object>();
    // 用来存储数据的有效期（过期时间戳）
    private Map<String, Long> expiryMap = new java.util.HashMap<String, Long>();
    // 检查过期的线程(线程池)
    private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    // 检查周期（默认6秒）
    private long expiryTime = 1000 * 6;

    /**
     * 默认构造函数，使用默认的检查周期
     */
    public ExpiryMap() {
        // 安排定期执行清理过期数据的任务
        service.scheduleAtFixedRate(this::clearExpiry, expiryTime, expiryTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 带参数的构造函数，可以自定义检查周期
     * @param expiryTime 检查周期（毫秒）
     */
    public ExpiryMap(long expiryTime) {
        this.expiryTime = expiryTime;
        // 安排定期执行清理过期数据的任务
        service.scheduleAtFixedRate(this::clearExpiry, expiryTime, expiryTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 添加键值对到map中，使用默认过期时间
     * @param key 键
     * @param value 值
     */
    public void put(String key, Object value) {
        map.put(key, value); // 存储键值对
        expiryMap.put(key, System.currentTimeMillis() + expiryTime); // 记录过期时间戳
    }

    /**
     * 添加键值对到map中，指定特定过期时间
     * @param key 键
     * @param value 值
     * @param expiryTime 特定的过期时间（毫秒）
     */
    public void put(String key, Object value, long expiryTime){
        map.put(key, value); // 存储键值对
        expiryMap.put(key, System.currentTimeMillis() + expiryTime); // 记录过期时间戳
    }

    /**
     * 获取指定键的值，如果已过期则返回null
     * @param key 键
     * @return 值或null（如果不存在或已过期）
     */
    public Object get(String key) {
        if (expiryMap.get(key) == null) { // 检查键是否存在
            return null;
        }
        if (expiryMap.get(key) < System.currentTimeMillis()) { // 检查是否过期
            map.remove(key); // 从数据map中移除
            expiryMap.remove(key); // 从过期时间map中移除
            return null;
        }
        return map.get(key); // 返回值
    }

    /**
     * 移除指定键的键值对
     * @param key 要移除的键
     */
    public void remove(String key) {
        map.remove(key); // 从数据map中移除
        expiryMap.remove(key); // 从过期时间map中移除
    }

    /**
     * 检查是否包含指定键且未过期
     * @param key 要检查的键
     * @return 如果包含且未过期返回true，否则返回false
     */
    public boolean containsKey(String key) {
        if (expiryMap.get(key) == null) { // 检查键是否存在
            return false;
        }
        if (expiryMap.get(key) < System.currentTimeMillis()) { // 检查是否过期
            map.remove(key); // 从数据map中移除
            expiryMap.remove(key); // 从过期时间map中移除
            return false;
        }
        return map.containsKey(key); // 检查数据map中是否包含该键
    }

    /**
     * 清除掉已经过期的key
     */
    public void clearExpiry(){
        // 遍历所有键
        for (String key : expiryMap.keySet()) {
            // 检查是否过期
            if (expiryMap.get(key) < System.currentTimeMillis()) {
                map.remove(key); // 从数据map中移除
                expiryMap.remove(key); // 从过期时间map中移除
            }
        }
    }
}
